package com.xbongbong.pro.statistics.strategy.chart.type.impl;

import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import com.xbongbong.paas.constant.XbbConstant;
import com.xbongbong.paas.elasticsearch.util.EsUtil;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.helper.PageHelper;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.pro.bi.commons.pojo.vo.GroupSqlVO;
import com.xbongbong.pro.domain.entity.ChartEntity;
import com.xbongbong.pro.statistic.help.ChartResultHelp;
import com.xbongbong.pro.statistic.help.DrillHelp;
import com.xbongbong.pro.statistic.result.pojo.ChartResultPojo;
import com.xbongbong.pro.statistic.result.pojo.ChartStatisticsPojo;
import com.xbongbong.pro.statistic.result.pojo.FieldAttrPojo;
import com.xbongbong.pro.statistic.result.pojo.vo.ChartAnalysisVO;
import com.xbongbong.pro.statistics.enums.StatisticsSumEnum;
import com.xbongbong.pro.statistics.help.AggregationlHelper;
import com.xbongbong.pro.statistics.help.CkResultHelp;
import com.xbongbong.pro.statistics.help.CommonHelper;
import com.xbongbong.pro.statistics.help.ComputedHelp;
import com.xbongbong.pro.statistics.help.DescribeTableHelper;
import com.xbongbong.pro.statistics.help.DisplayHelper;
import com.xbongbong.pro.statistics.help.InitSqlHelper;
import com.xbongbong.pro.statistics.help.StatisticsTableVOHelper;
import com.xbongbong.pro.statistics.pojo.dto.ChartAnalysisDTO;
import com.xbongbong.pro.statistics.pojo.dto.GenerateSqlDTO;
import com.xbongbong.pro.statistics.pojo.vo.GenerateSqlVO;
import com.xbongbong.pro.statistics.strategy.chart.type.ChartTypeStrategyService;
import com.xbongbong.saas.service.toolbox.help.AttrDecimalPrecisionHelper;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

import static com.xbongbong.pro.statistics.enums.StatisticsSumEnum.getEnumBySum;
import static com.xbongbong.pro.statistics.help.InitSqlHelper.getIsMaxPermission;


/**
 * 统计表
 * @author xinpeng.jiang
 * @date 2021/11/10 19:17
 * @version 1.0
 * @since V1.0
 */
@Service
public class DataStatisticsTableStrategyServiceImpl implements ChartTypeStrategyService {

    @Resource
    private CkResultHelp ckResultHelp;
    @Resource
    private ChartResultHelp chartResultHelp;
    @Resource
    private InitSqlHelper initSqlHelper;
    @Resource
    private AggregationlHelper aggregationlHelper;
    @Resource
    private CommonHelper commonHelper;
    @Resource
    private AttrDecimalPrecisionHelper attrDecimalPrecisionHelper;
    @Resource
    private DisplayHelper displayHelper;
    @Resource
    private DescribeTableHelper describeTableHelper;
    @Resource
    private StatisticsTableVOHelper statisticsTableVOHelper;
    @Resource
    private ComputedHelp computedHelp;
    @Resource
    private DrillHelp drillHelp;

    public Logger logger = LoggerFactory.getLogger(getClass());

    @Override
    public ChartAnalysisVO chartAnalysis(ChartAnalysisDTO chartAnalysisDTO) throws XbbException {
        Map<String, Map<String, String>> attrLinkMap = aggregationlHelper.getLinkMap(chartAnalysisDTO.getChartEntity(),  chartAnalysisDTO.getResultArray());
        return statisticsTableVOHelper.statisticsChartAnalysis(chartAnalysisDTO,attrLinkMap);
    }


    /**
     * 获取总条数
     * @param body 数据
     * @return int 总条数
     * @author xinpeng.jiang
     * @date 2021/12/8 19:18
     * @version 1.0
     */
    private int getRowsCount(List<ChartStatisticsPojo> body) {
        if (CollectionsUtil.isEmpty(body)) {
            return 0;
        }
        ChartStatisticsPojo chartStatisticsPojo = body.get(0);
        List<ChartStatisticsPojo> child = chartStatisticsPojo.getChild();
        if (CollectionsUtil.isNotEmpty(child)) {
            return getRowsCount(child);
        } else {
            List<String> values = chartStatisticsPojo.getValues();
            if (CollectionsUtil.isNotEmpty(values)) {
                return values.size();
            }
        }
        return 0;
    }

    @Override
    public GenerateSqlVO generateSql(GenerateSqlDTO generateSqlDTO) throws XbbException {
        GenerateSqlVO generateSqlVO = new GenerateSqlVO();
        ChartEntity chartEntity = generateSqlDTO.getChartEntity();
        //行列分组的时候
        if (chartEntity.getRowGroupAttr()==null || chartEntity.getColGroupAttr()==null ||((chartEntity.getRowGroupAttr()!=null && chartEntity.getRowGroupAttr().size() <= 0) && (chartEntity.getColGroupAttr()!=null && chartEntity.getColGroupAttr().size() <= 0))) {
            return generateSqlVO;
        }
        //统计表没有选择汇总字段直接返回
        if(chartEntity.getSummaryAttr()==null || chartEntity.getSummaryAttr().size()<=0){
            return generateSqlVO;
        }
        ChartResultPojo chartResultPojo = generateSqlDTO.getChartResultPojo();
        boolean isSingle = generateSqlDTO.getSingle();
        StringBuffer stringBuffer = new StringBuffer();
        Map<Long, String> formIdTableMap = commonHelper.getFormIdTableMap(chartEntity, isSingle);
        //筛选+查询
        Map<String,StringBuffer>  fliterMap = new HashMap<>(XbbConstant.INITIALCAPACITY);
        initSqlHelper.parseConditionIntersection(fliterMap, chartEntity, false);
        Map<String, String> sortFieldMap = displayHelper.getAggSortMap(chartEntity, chartResultPojo.getSortStatisticsMap(),chartResultPojo.getSortFieldOrder());
        //聚合条件 要放置两份，一份在colums,一份在group BY
        Pair<GroupSqlVO, HashMap<String, Set<String>>> groupSqlVOHashMapPair = aggregationlHelper.statisticTableAggregation(chartEntity, formIdTableMap, sortFieldMap);
        GroupSqlVO groupSqlVO = groupSqlVOHashMapPair.getKey();
        List<String> groupFieldsList = groupSqlVO.getGroupFieldsList();
        List<String> aggFieldsList = groupSqlVO.getAggFieldsList();
        List<String> sumTotalFieldsList = groupSqlVO.getSumTotalFieldsList();
        List<String> groupColumnsList  = groupSqlVO.getGroupColumnsList();
        StringBuffer gropuColumns  = new StringBuffer();
        getJoingBuf(groupColumnsList,gropuColumns);
        StringBuffer gropuFields  = new StringBuffer();
        getJoingBuf(groupFieldsList, gropuFields);
        StringBuffer aggFields  = new StringBuffer();
        getJoingBuf(aggFieldsList,aggFields);
        if(CollectionUtils.isNotEmpty(groupColumnsList)){
            if(StringUtil.isNotEmpty(aggFields.toString())){
                aggFields.append(",");
            }
            aggFields.append(gropuColumns);
        }
        //构建子查询外层SQL语句的返回字段
        initSqlHelper.buildSubColumnOfCount(groupSqlVO,groupColumnsList,Boolean.TRUE);

        String sortField = displayHelper.getAggSortField(sortFieldMap,groupSqlVO);
        boolean isMaxPermission = getIsMaxPermission(chartResultPojo);

        int limit = 1000;
        limit = describeTableHelper.statisticsLimit(chartEntity, chartResultPojo, limit);
        initSqlHelper.tableJoin(groupSqlVOHashMapPair,chartEntity, isSingle, stringBuffer, aggFields, sortField, fliterMap, limit, 0,gropuFields.toString(),isMaxPermission);
        //分页
        int pageSize =  XbbConstant.STATISTICS_PAGE_SIZE;
        PageHelper pageHelper = new PageHelper(chartResultPojo.getPage(), pageSize);
        generateSqlVO.setPageHelper(pageHelper);
        generateSqlVO.setStringBufferSql(stringBuffer);
        //统计表总计、小计的sql处理
        totalOrSubtotalSqlHandle(generateSqlVO, chartEntity, stringBuffer, groupSqlVO, sumTotalFieldsList,formIdTableMap,sortFieldMap);
        generateSqlVO.setAggFieldMap(groupSqlVO.getAggFieldMap());
        return generateSqlVO;
    }

    /**
     * 统计表的小计值、总计值，会拼接sql，并发起请求从数据库中获取
     *
     * @param generateSqlVO 拼接sql的vo实体
     * @param chartEntity 图表实体
     * @param resultSql 统计表源数据sql
     * @param groupSqlVO  分组sql vo
     * @param sumTotalFieldsList 汇总字段的sql数组
     * @author zyy
     * @date 2022/8/26
     * @version v1.0
     */
    private void totalOrSubtotalSqlHandle(GenerateSqlVO generateSqlVO, ChartEntity chartEntity, StringBuffer resultSql, GroupSqlVO groupSqlVO, List<String> sumTotalFieldsList,Map<Long, String> formIdTableMap,Map<String, String> sortFieldMap) throws XbbException {
        //如果是子查询SQL，那么原有的result Sql语句是完整的子查询SQL，内层的存到groupSqlVO里了
        if(StringUtils.isNotBlank(groupSqlVO.getSubCompleteSqlOfCount())){
            resultSql = new StringBuffer(groupSqlVO.getSubCompleteSqlOfCount());
        }
        StatisticsSumEnum statisticsSumEnum = getEnumBySum(chartEntity.getSum());
        switch (statisticsSumEnum) {
            case SUB_TOTAL:
                //小计
                subtotalSqlHandle(generateSqlVO,chartEntity,resultSql,groupSqlVO,sumTotalFieldsList,formIdTableMap,sortFieldMap);
                break;
            case ALL:
                //总计 & 小计
                subtotalSqlHandle(generateSqlVO,chartEntity,resultSql,groupSqlVO,sumTotalFieldsList,formIdTableMap,sortFieldMap);
                totalSqlHandle(generateSqlVO,resultSql,groupSqlVO,sumTotalFieldsList);
                break;
            default:
                //默认为总计
                totalSqlHandle(generateSqlVO,resultSql,groupSqlVO,sumTotalFieldsList);
                break;
        }
    }

    /**
     * 获取小计sql (最下方小计)
     *
     * @param generateSqlVO
     * @param chartEntity
     * @param resultSql
     * @param groupSqlVO
     * @param sumTotalFieldsList
     * @author zyy
     * @date 2022/8/3
     * @version v1.0
     */
    private void subtotalSqlHandle(GenerateSqlVO generateSqlVO, ChartEntity chartEntity, StringBuffer resultSql, GroupSqlVO groupSqlVO, List<String> sumTotalFieldsList,Map<Long, String> formIdTableMap,Map<String, String> sortFieldMap) throws XbbException {
        //没有行分组则不计算小计
        if(CollectionUtils.isEmpty(groupSqlVO.getRowGroupColumnsList())){
            return;
        }
        //获取group部分
        //获取行分组,只获取第一层
        List<String> subTotalGroupColumnList = new ArrayList<>();
        List<String> subTotalGroupFieldList = new ArrayList<>();

        JSONObject originalRowField = chartEntity.getOriginalRowField();
        if(Objects.nonNull(originalRowField)){
            FieldAttrPojo fieldAttrPojo = originalRowField.toJavaObject(FieldAttrPojo.class);
            initSqlHelper.addFieldaliasList(Maps.newHashMap(), EsUtil.getSingle(chartEntity), subTotalGroupColumnList, subTotalGroupFieldList, formIdTableMap,
                    fieldAttrPojo, fieldAttrPojo.getAttr(), fieldAttrPojo.getFormId(), sortFieldMap, chartEntity,Maps.newHashMap(),new ArrayList<>(),new ArrayList<>());
        }else{
            subTotalGroupColumnList.add(groupSqlVO.getRowGroupColumnsList().get(0));
            subTotalGroupFieldList.add(groupSqlVO.getRowGroupFieldsList().get(0));
        }

        //获取列分组,获取到最后一层
        if(CollectionUtils.isNotEmpty(groupSqlVO.getColGroupColumnsList())){
            subTotalGroupColumnList.addAll(groupSqlVO.getColGroupColumnsList());
            subTotalGroupFieldList.addAll(groupSqlVO.getColGroupFieldsList());
        }
        String groupColumn = String.join(",",subTotalGroupColumnList);
        String groupField = String.join(",",subTotalGroupFieldList);

        //from部分
        String fromSql = getFromSqlOfTotal(resultSql);

        //select部分
        String subTotalSql = getSelectSqlOfTotal(sumTotalFieldsList, groupColumn, groupField, fromSql);
        //子查询SQL处理
        subTotalSql = statisticsTableVOHelper.dealSubQuerySqlByCount(subTotalSql,groupSqlVO,groupColumn,Boolean.TRUE);
        generateSqlVO.setSubTotalSql(subTotalSql);
    }

    /**
     * 获取总计sql  （最下方总计、最右侧总计）
     *
     * @param generateSqlVO
     * @param resultSql
     * @param groupSqlVO
     * @param sumTotalFieldsList
     * @author zyy
     * @date 2022/7/25
     * @version v1.0
     */
    private void totalSqlHandle(GenerateSqlVO generateSqlVO, StringBuffer resultSql, GroupSqlVO groupSqlVO, List<String> sumTotalFieldsList) throws XbbException {
        //最下方总计处理(第三象限)
        //group 部分
        Map<String,String> groupSqlMap = statisticsTableVOHelper.getGroupSqlOfTotal(groupSqlVO,true);
        //from 部分
        String fromSql = getFromSqlOfTotal(resultSql);
        //select 部分
        String underSelect = getSelectSqlOfTotal(sumTotalFieldsList,groupSqlMap.get("groupColumn"),groupSqlMap.get("groupField"),fromSql);
        //子查询SQL处理
        underSelect = statisticsTableVOHelper.dealSubQuerySqlByCount(underSelect,groupSqlVO,groupSqlMap.get("groupColumn"),Boolean.TRUE);
        generateSqlVO.setSumTotalSql(underSelect);

        //最右侧总计sql（第一象限）
        //group部分
        Map<String,String> rightGroupSqlMap = statisticsTableVOHelper.getGroupSqlOfTotal(groupSqlVO,false);
        //select 部分
        String rightSelect = getSelectSqlOfTotal(sumTotalFieldsList,rightGroupSqlMap.get("groupColumn"),rightGroupSqlMap.get("groupField"),fromSql);
        //子查询SQL处理
        rightSelect = statisticsTableVOHelper.dealSubQuerySqlByCount(rightSelect,groupSqlVO,rightGroupSqlMap.get("groupColumn"),Boolean.TRUE);
        generateSqlVO.setSumRightTotalSql(rightSelect);

        //总计的总计（第四象限）
        if(statisticsTableVOHelper.containsComputedField(groupSqlVO.getAggFieldMap(),groupSqlVO.getColGroupColumnsList())){
            //只拼接 select部分 跟 from部分 ，不进行分组（最大的数据范围）
            String totalOfTotalSql = getSelectSqlOfTotal(sumTotalFieldsList,"","",fromSql);
            //子查询SQL处理
            totalOfTotalSql = statisticsTableVOHelper.dealSubQuerySqlByCount(totalOfTotalSql,groupSqlVO,"",Boolean.TRUE);
            generateSqlVO.setTotalOfTotalSql(totalOfTotalSql);
        }
    }

    /**
     * 统计表总计sql - select部分
     *
     * @param sumTotalFieldsList 汇总字段
     * @param groupColum group部分sql
     * @param groupField 分组字段sql
     * @param fromSql    from部分sql
     * @return java.lang.String
     * @author zyy
     * @date 2022/7/27
     * @version v1.0
     */
    private String getSelectSqlOfTotal(List<String> sumTotalFieldsList,String groupColum, String groupField,String fromSql) {
        String newSql = "select ";
        if (CollectionUtils.isNotEmpty(sumTotalFieldsList)) {
            newSql += String.join(",", sumTotalFieldsList);
            newSql += "".equals(groupField) ? "" : ",";
        }
        newSql += groupColum + " from " + fromSql;
        if (!"".equals(groupField)) {
            newSql += " GROUP BY " + groupField;
        }
        return newSql;
    }

    /**
     * 统计表总计sql - from部分
     *
     * @param resultSql
     * @return java.lang.String
     * @author zyy
     * @date 2022/7/27
     * @version v1.0
     */
    private String getFromSqlOfTotal(StringBuffer resultSql) {
        String[] array = resultSql.toString().split("from", 2);
        String oldSql = array[1];
        if (oldSql.contains("GROUP BY")) {
            oldSql = oldSql.substring(0, oldSql.lastIndexOf("GROUP BY"));
        }
        return oldSql;
    }

    /**
     * @Description joing List并append到StringBuffer
     * @Date 10:17 2021/12/24
     * @Param [fieldsList, fields]
     * @return void
     * @throws
     **/

    private void getJoingBuf(List<String> fieldsList, StringBuffer fields) {
        if (fieldsList != null){
            fields.append(String.join(",", fieldsList));
        }
    }

}
